package cn.tannn.ops.customer.controller;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.tree.Tree;
import cn.tannn.jdevelops.annotations.web.authentication.ApiPlatform;
import cn.tannn.jdevelops.annotations.web.constant.PlatformConstant;
import cn.tannn.jdevelops.annotations.web.mapping.PathRestController;
import cn.tannn.jdevelops.exception.built.BusinessException;
import cn.tannn.jdevelops.exception.built.UserException;
import cn.tannn.jdevelops.jpa.constant.SQLOperator;
import cn.tannn.jdevelops.jpa.result.JpaPageResult;
import cn.tannn.jdevelops.jwt.redis.service.RedisLoginService;
import cn.tannn.jdevelops.jwt.redis.service.RedisUserRole;
import cn.tannn.jdevelops.jwt.redis.util.RsJwtWebUtil;
import cn.tannn.jdevelops.result.response.ResultPageVO;
import cn.tannn.jdevelops.result.response.ResultVO;
import cn.tannn.jdevelops.result.utils.ListTo;
import cn.tannn.ops.customer.constant.RoleDef;
import cn.tannn.ops.customer.controller.dto.RoleAdd;
import cn.tannn.ops.customer.controller.dto.RoleAlter;
import cn.tannn.ops.customer.controller.dto.RoleMenus;
import cn.tannn.ops.customer.controller.dto.RolePage;
import cn.tannn.ops.customer.controller.vo.MenuVO;
import cn.tannn.ops.customer.controller.vo.RoleVO;
import cn.tannn.ops.customer.entity.Customer;
import cn.tannn.ops.customer.entity.Menu;
import cn.tannn.ops.customer.entity.Role;
import cn.tannn.ops.customer.entity.RoleMenu;
import cn.tannn.ops.customer.service.*;
import cn.tannn.ops.util.TreeUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.*;

import static cn.tannn.jdevelops.utils.jwt.exception.TokenCode.TOKEN_ERROR;


/**
 * 角色
 *
 * @author <a href="https://tannn.cn/">tan</a>
 * @date 2023/12/4 13:19
 */
@Tag(name = "角色管理")
@PathRestController("role")
@RequiredArgsConstructor
@Slf4j
public class RoleController {

    private final RoleService roleService;
    private final RoleMenuService roleMenuService;
    private final RoleCustomerService roleCustomerService;
    private final MenuService menuService;
    private final CustomerService customerService;
    private final RedisUserRole redisUserRole;
    private final RedisLoginService redisLoginService;

    @PostMapping("add")
    @Operation(summary = "新增角色")
    @ApiOperationSupport(order = 1)
    @ApiPlatform(platform = PlatformConstant.WEB_ADMIN)
    public ResultVO<String> addRole(@RequestBody @Valid RoleAdd authRole) {
        if (RoleDef.NO_REGIST_ROLE.contains(authRole.getName()) ||
            RoleDef.NO_REGIST_ROLE.contains(authRole.getCode())) {
            return ResultVO.failMessage("注册非法角色");
        }
        if (roleService.registerRole(authRole)) {
            if (log.isDebugEnabled()) {
                log.debug("add role success: {}", authRole);
            }
            return ResultVO.success();
        } else {
            return ResultVO.failMessage("角色已存在");
        }
    }


    @PostMapping("alter")
    @Operation(summary = "编辑角色")
    @ApiOperationSupport(order = 2)
    @ApiPlatform(platform = PlatformConstant.WEB_ADMIN)
    public ResultVO<String> alterRole(@RequestBody @Valid RoleAlter role) {
        if (RoleDef.NO_REGIST_ROLE.contains(role.getCode())) {
            return ResultVO.failMessage("系统内置角色不允许编辑");
        }
        // 名称、代号验重
        Assert.isFalse(roleService.verifyRoleExist(role.getName()),
                () -> new BusinessException("当前角色名称已存在，请重新填写"));
        roleService.update(role, SQLOperator.EQ, "code");
        return ResultVO.successMessage("修改成功");
    }


    @PostMapping("enabled")
    @Operation(summary = "启用角色", description = "无法操作内置角色")
    @ApiOperationSupport(order = 3)
    @ApiPlatform(platform = PlatformConstant.WEB_ADMIN)
    public ResultVO<String> enabled(@RequestBody List<String> codes) {
        roleService.enable(codes);
        return ResultVO.successMessage("启用成功");
    }


    @PostMapping("disable")
    @Operation(summary = "禁用角色", description = "无法操作内置角色")
    @ApiOperationSupport(order = 4)
    @ApiPlatform(platform = PlatformConstant.WEB_ADMIN)
    public ResultVO<String> disable(@RequestBody List<String> codes) {
        roleService.disabled(codes);
        List<String> loginNames = roleCustomerService.deleteByRoleCode(codes);
        loginNames.forEach(redisLoginService::loginOut);
        return ResultVO.successMessage("禁用成功");
    }

    @PostMapping("delete")
    @Operation(summary = "真实删除", description = "无法操作内置角色")
    @ApiOperationSupport(order = 5)
    @Transactional(rollbackFor = Exception.class)
    @ApiPlatform(platform = PlatformConstant.WEB_ADMIN)
    public ResultVO<String> delete(@RequestBody List<String> codes) {
        // 存在交集
        if (!Collections.disjoint(RoleDef.NO_REGIST_ROLE, codes)) {
            return ResultVO.failMessage("系统内置角色不允许被删除");
        }
        roleService.deleteByCodes(codes);
        // 删除角色菜单关联关系
        roleMenuService.deleteByRoleCode(codes);
        // 删除角色用户关联关系
        List<String> loginNames = roleCustomerService.deleteByRoleCode(codes);
        loginNames.forEach(redisLoginService::loginOut);
        return ResultVO.successMessage("删除成功");
    }


    @PostMapping("select")
    @Operation(summary = "模糊查询且分页")
    @ApiOperationSupport(order = 6)
    public ResultPageVO<RoleVO, JpaPageResult<RoleVO>> selectRole(@RequestBody @Valid RolePage role) {
        Page<Role> roles = roleService.findPage(role, role.getPage());
        JpaPageResult<RoleVO> pageResult = JpaPageResult.toPage(roles, RoleVO.class);
        return ResultPageVO.success(pageResult, "查询成功");
    }

    @GetMapping("findMenu")
    @Operation(summary = "查询角色功能节点集")
    @Parameter(description = "角色code", name = "roleCode", required = true)
    @ApiOperationSupport(order = 7)
    @ApiPlatform(platform = PlatformConstant.WEB_ADMIN)
    public ResultVO<List<MenuVO>> getRoleMenu(String roleCode) {
        List<String> menuCodes = roleMenuService.getMenuCodesByRoleCode(roleCode);
        List<Menu> menus = menuService.findByCode(menuCodes);
        return ResultVO.success("查询成功", ListTo.to(MenuVO.class, menus));
    }

    @PostMapping("setMenu")
    @Operation(summary = "角色设置菜单")
    @ApiOperationSupport(order = 8)
    @ApiPlatform(platform = PlatformConstant.WEB_ADMIN)
    public ResultVO<String> setRoleMenu(@RequestBody @Valid RoleMenus roleMenus) {
        boolean b = roleMenuService.deleteByRoleCode(roleMenus.getRoleCode());
        if (!b) {
            return ResultVO.failMessage("操作失败");
        }
        if (!roleMenus.getMenuCodes().isEmpty()) {
            List<RoleMenu> list = new ArrayList<>();
            for (String menuCode : roleMenus.getMenuCodes()) {
                RoleMenu roleMenu = new RoleMenu();
                roleMenu.setRoleCode(roleMenus.getRoleCode());
                roleMenu.setMenuCode(menuCode);
                list.add(roleMenu);
            }
            roleMenuService.saves(list);
        }
        return ResultVO.resultMsg(b, "操作");

    }

    @GetMapping("findUser")
    @Operation(summary = "查询角色的用户集")
    @ApiOperationSupport(order = 9)
    @ApiPlatform(platform = PlatformConstant.WEB_ADMIN)
    public ResultVO<List<Map<String, Object>>> getRoleUser(String roleCode) {
        List<Long> userIds = roleCustomerService.getUserIdByRoleCode(roleCode);
        List<Customer> users = customerService.findByIds(userIds);
        List<Map<String, Object>> userList = new ArrayList<>();
        for (Customer user : users) {
            Map<String, Object> map = new HashMap<>(3);
            map.put("userId", user.getId().toString());
            map.put("loginName", user.getLoginName());
            map.put("name", user.getName());
            userList.add(map);
        }
        return ResultVO.success("查询成功", userList);
    }


    @GetMapping("getPower")
    @Operation(summary = "获取用户角色所拥有的菜单树")
    @ApiOperationSupport(order = 11)
    @ApiPlatform(platform = PlatformConstant.WEB_ADMIN)
    public ResultVO<List<Tree<String>>> getPower(HttpServletRequest request) {
        List<Menu> beans = null;
        List<String> menuCodes;
        String loginNameByToke = RsJwtWebUtil.getTokenSubjectExpires(request);
        Optional<Customer> byLoginName = customerService.findByLoginName(loginNameByToke);
        // 用户不存在
        Customer userEntity = byLoginName.orElseThrow(() -> new UserException(TOKEN_ERROR));

        // 查询权限code
        List<String> roleCodes = roleCustomerService.getRoleCodeByUserId(userEntity.getId());
        // 无权限给与默认权限
        if (roleCodes.isEmpty()) {
            roleService.findByCode(RoleDef.USER_COMMON).ifPresent(role -> roleCodes.add(role.getCode()));
        }
        // 该账户是超管用户直接给权
        if (roleCodes.contains(RoleDef.USER_ADMIN)) {
            beans = menuService.getAllExDisabled();
        } else {
            // 查询权限拥有的菜单列表
            menuCodes = roleMenuService.getMenuCodesByRoleCode(roleCodes);
            beans = menuService.findByMenuStatusAndCodeIn(1, menuCodes);
        }

        if (beans != null) {
            List<Tree<String>> treeNodes = TreeUtil.menusTree(beans);
            return ResultVO.success("获取用户权限成功", treeNodes);
        } else {
            return ResultVO.failMessage("数据获取失败");
        }

    }

    @GetMapping("roles")
    @Operation(summary = "查询角色集(只有正常的角色)")
    @ApiOperationSupport(order = 12)
    public ResultVO<List<RoleVO>> getRoleResPermission() {
        List<Role> enable = roleService.findEnable();
        List<RoleVO> to = ListTo.to(RoleVO.class, enable);
        return ResultVO.success("查询成功", to);
    }

}
